#include "routing/ip_packet.h"

const int CIPPacket::sMaxPacketLength = 65535;

CIPPacket::CIPPacket(uint8_t* pForeignPacketBuffer, int pBufferLength)
{
	/* initialize the memory area for networking data */
#ifdef MEMCPY
	mPacketBuffer = new uint8_t[pBufferLength];
	memcpy(mPacketBuffer, pForeignPacketBuffer, pBufferLength);
#else
	mPacketBuffer = pForeignPacketBuffer;
#endif
	mBufferLength = pBufferLength;

	/* adjust the pointers */
	mIP_header = reinterpret_cast<struct iphdr*>(mPacketBuffer);
	mUDP_header = reinterpret_cast<struct udphdr*>(mPacketBuffer + sizeof(struct iphdr));
	mTCP_header = reinterpret_cast<struct tcphdr*>(mPacketBuffer + sizeof(struct iphdr));
	mPayload = mPacketBuffer + sizeof(struct iphdr);
}

CIPPacket::~CIPPacket()
{
	mIP_header = NULL;
	mUDP_header = NULL;
	mTCP_header = NULL;
	mPayload = NULL;

#ifdef MEMCPY
	delete[] mPacketBuffer;
#endif
}

CIPPacket* CIPPacket::createIPPacket(uint8_t* pForeignPacketBuffer, int pBufferLength)
{
	return new CIPPacket(pForeignPacketBuffer, pBufferLength);
}

int CIPPacket::destroyIPPacket(CIPPacket* pIPPacket)
{
	delete pIPPacket;
	return 0; /* success */
}

bool CIPPacket::isUDP() const
{
	return (mIP_header->protocol == IPPROTO_UDP);
}

bool CIPPacket::isTCP() const
{
	return (mIP_header->protocol == IPPROTO_TCP);
}

uint32_t CIPPacket::getSrcIP() const
{
	return mIP_header->saddr;
}

uint32_t CIPPacket::getDstIP() const
{
	return mIP_header->daddr;
}

int CIPPacket::getSrcPort() const
{
	if(isUDP())
	{
		return mUDP_header->source;
	}

	return -1;
}

int CIPPacket::getDstPort() const
{
	if(isUDP())
	{
		return mUDP_header->dest;
	}
	
	return -1;
}

uint8_t* CIPPacket::getPayload() const
{
	/* check whether packet is a UDP or TCP packet and return proper pointer to the payload */
	uint8_t* lPayloadPtr = mPacketBuffer + sizeof(struct iphdr);

	if(isUDP())
	{
		lPayloadPtr += sizeof(struct udphdr);
	}
	else if(isTCP())
	{
		lPayloadPtr += sizeof(struct tcphdr);
	}
	else
	{
		lPayloadPtr = NULL;
	}

	return lPayloadPtr; /* TODO */
}

uint8_t* CIPPacket::getPacketBuffer() const
{
	return mPacketBuffer;
}

int CIPPacket::getPayloadLength() const
{
	int lReturn = -1; /* everything else not supported */

	if(isUDP())
	{
		lReturn = ntohs(mUDP_header->len) - sizeof(struct udphdr);
	}
	else if(isTCP())
	{
		lReturn = -1; /* TODO not supported currently */
	}

	return lReturn;
}

void CIPPacket::calcChecksum()
{
	libnet_do_checksum(NULL,
		mPacketBuffer,
		mIP_header->protocol,
		mBufferLength - LIBNET_IPV4_H);
}

